package cn.melonlib.cores.commons.comp.service.impl;

import cn.melonlib.cores.commons.comp.service.BasicService;
import cn.melonlib.cores.commons.comp.service.UpdateHandler;
import cn.melonlib.cores.commons.model.entity.IEntity;
import cn.melonlib.cores.jpa.comp.Dao;
import cn.melonlib.cores.jpa.model.bean.PaginationListResult;
import cn.melonlib.cores.jpa.model.bean.PersistenceResult;
import cn.melonlib.cores.jpa.model.bean.Query;
import cn.melonlib.cores.jpa.model.bean.collections.EntityMap;
import cn.melonlib.cores.jpa.model.bean.impl.DefaultQueryResult;
import cn.melonlib.cores.jpa.model.bean.impl.DefaultUpdateResult;
import cn.melonlib.cores.jpa.model.bean.impl.PaginationList;
import lombok.Getter;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.io.Serializable;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Getter
public class BasicServiceImpl implements BasicService {

    @Resource
    private Dao dao;

    @Override
    public <DATA> PersistenceResult<DATA> search(Query query) throws Exception {
        return (PersistenceResult<DATA>)this.search(query,e->new EntityMap((IEntity<? extends Serializable>) e));
    }

    @Override
    public <ENTITY,DATA> PersistenceResult<DATA> search(Query query, Function<ENTITY, DATA> transform) throws Exception {
        PersistenceResult<Object> datasResult=dao.search(query);
        Object datas=datasResult.getResult();
        if(datas instanceof PaginationList){
            DATA result=(DATA) PaginationList.createOffset(((PaginationListResult<ENTITY>) datas).getData().stream().map(transform).collect(Collectors.toList())
            ,((PaginationListResult<?>) datas).getOffset(),((PaginationListResult<?>) datas).getLimit(),((PaginationListResult<?>) datas).getTotal());
            return new DefaultQueryResult<DATA>(result);
        }else if(datas instanceof List){
            DATA result= (DATA) ((List<ENTITY>) datas).stream().map(transform).collect(Collectors.toList());
            return new DefaultQueryResult<>(result);
        }else{
            return new DefaultQueryResult<DATA>((DATA)datas);
        }
    }

    @Override
    public <ENTITY extends IEntity<PK>,PK extends Serializable> ENTITY getEntity(Class<ENTITY> entityClass, PK id) {
        return dao.<ENTITY,PK>getEntity(entityClass,id);
    }


    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public PersistenceResult<Integer> updateWork(Function<Dao,Integer> worker) {
        return new DefaultUpdateResult<>(worker.apply(dao));
    }

    @Override
    public <DATA> PersistenceResult<DATA> queryWork(Function<Dao, DATA> worker) {
        return new DefaultQueryResult<DATA>(worker.apply(dao));
    }

    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public <ENTITY extends IEntity<? extends Serializable>> PersistenceResult<ENTITY> save(ENTITY entity) throws Exception {
        return dao.save(entity);
    }

    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public <ENTITY extends IEntity<? extends Serializable>> PersistenceResult<ENTITY> save(ENTITY entity, UpdateHandler<ENTITY, Integer> before, UpdateHandler<ENTITY, Integer> post) throws Exception {
        before.update(dao,entity);
        PersistenceResult<ENTITY> saveResult=dao.save(entity);
        post.update(dao,saveResult.getResult());
        return saveResult;
    }

    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public <ENTITY extends IEntity<? extends Serializable>> PersistenceResult<Integer> remove(ENTITY entity) throws Exception {
        return dao.remove(entity);
    }

    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public <ENTITY extends IEntity<? extends Serializable>> PersistenceResult<Integer> remove(ENTITY entity, UpdateHandler<ENTITY, Integer> before, UpdateHandler<ENTITY, Integer> post) throws Exception {
        int rowNum=before.update(dao,entity);
        dao.remove(entity);
        rowNum+=post.update(dao,entity);
        return new DefaultUpdateResult<>(rowNum);
    }

    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public <ENTITY extends IEntity<? extends Serializable>> PersistenceResult<Integer> removeById(Class<ENTITY> entityClass, String id) throws Exception {
        this.dao.removeById(entityClass,id);
        return new DefaultUpdateResult<>(1);
    }

    @Override
    @Transactional(value = Transactional.TxType.REQUIRED,rollbackOn = {Exception.class})
    public <ENTITY extends IEntity<? extends Serializable>> PersistenceResult<Integer> removeById(Class<ENTITY> entityClass, String id, UpdateHandler<String, Integer> before, UpdateHandler<ENTITY, Integer> post) throws Exception {
        ENTITY entity=dao.getEntity(entityClass,id);
        int rowNum=before.update(dao,id);
        dao.removeById(entityClass,id);
        rowNum+=post.update(dao,entity);
        return new DefaultUpdateResult<>(rowNum);
    }
}
